using System;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.BulkCopy;
using OracleInternal.Common;
using OracleInternal.MTS;
using OracleInternal.TTC;

namespace OracleInternal.ServiceObjects
{
	internal class OracleBulkCopyImpl
	{
		private OracleBulkCopy m_bulkCopy;

		private OracleConnectionImpl m_connImpl;

		private TTCDirectPathPrepare m_ttcDPPrepare;

		private TTCDirectPathLoadStream m_ttcDPLoadStream;

		private TTCDirectPathMOP m_ttcDPMOP;

		private DirectPathContext m_DPContext;

		private IBulkCopyDataSource m_dataSource;

		private OracleBulkCopyColumnMappingCollection m_internalColumnMappings;

		private string m_schemaName = string.Empty;

		private string m_tableName = string.Empty;

		private string m_partitionName = string.Empty;

		private int m_numOfRowsToNotify;

		private bool m_resetAutoCommit = true;

		private DirectPathStream m_stream = new DirectPathStream();

		internal OracleBulkCopyImpl(OracleBulkCopy bulkCopy)
		{
			m_bulkCopy = bulkCopy;
			m_connImpl = bulkCopy.Connection.m_oracleConnectionImpl;
			bool flag = m_connImpl.m_mtsTxnCtx != null && m_connImpl.m_mtsTxnCtx.m_txnType != MTSTxnType.None;
			bool bInTxn = bulkCopy.Connection.m_oraTransaction != null || flag;
			m_DPContext = new DirectPathContext();
			m_ttcDPPrepare = new TTCDirectPathPrepare(m_connImpl.m_marshallingEngine, bInTxn);
			m_ttcDPLoadStream = new TTCDirectPathLoadStream(m_connImpl.m_marshallingEngine);
			m_ttcDPMOP = new TTCDirectPathMOP(m_connImpl.m_marshallingEngine);
		}

		internal void Init(IBulkCopyDataSource dataSource, OracleBulkCopyColumnMappingCollection internalColumnMappings, string schemaName, string tableName, string partitionName)
		{
			m_dataSource = dataSource;
			m_internalColumnMappings = internalColumnMappings;
			m_schemaName = schemaName;
			m_tableName = tableName;
			m_partitionName = partitionName;
			m_numOfRowsToNotify = m_bulkCopy.NotifyAfter;
		}

		internal ColumnDescribeInfo[] Prepare()
		{
			string[] array = new string[m_internalColumnMappings.Count];
			int num = 0;
			foreach (OracleBulkCopyColumnMapping internalColumnMapping in m_internalColumnMappings)
			{
				array[num++] = internalColumnMapping.DestinationColumn;
			}
			try
			{
				m_resetAutoCommit = m_connImpl.m_autoCommit;
				if (m_connImpl.m_autoCommit)
				{
					m_connImpl.SetAutoCommit(bAutoCommitOn: false);
				}
				m_ttcDPPrepare.Init(m_schemaName, m_tableName, m_partitionName, array);
				m_connImpl.m_connectionFreeToUseEvent.WaitOne();
				m_connImpl.AddAllPiggyBackRequests();
				m_ttcDPPrepare.Prepare(out m_DPContext);
				return m_DPContext.m_columnsMetaData;
			}
			finally
			{
				m_connImpl.m_connectionFreeToUseEvent.Set();
			}
		}

		internal void LoadRows(BulkCopyRows rows)
		{
			DirectPathRow directPathRow = null;
			try
			{
				for (int i = 0; i < rows.m_numOfRowsProcessed; i++)
				{
					directPathRow = DirectPathStreamPlanner.CreateDirectPathRow(rows.m_bAllfastColumns, rows.m_bindingRows[i]);
					if (!m_stream.Add(directPathRow, rows.m_bindingRows[i]))
					{
						LoadStream(m_stream);
						m_stream.ResetForNextStream();
					}
				}
			}
			finally
			{
				rows.Reset();
			}
		}

		internal void LoadStream(DirectPathStream dpStream)
		{
			try
			{
				m_connImpl.m_connectionFreeToUseEvent.WaitOne();
				m_connImpl.AddAllPiggyBackRequests();
				m_ttcDPLoadStream.LoadStream(dpStream);
			}
			finally
			{
				m_connImpl.m_connectionFreeToUseEvent.Set();
			}
		}

		internal BulkCopyResult ProcessBatch(int numOfRows)
		{
			try
			{
				m_ttcDPLoadStream.Init(m_DPContext);
				return InternalProcessBatch(numOfRows, bUseArray: true);
			}
			catch (Exception ex)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BulkCopy, OracleTraceClassName.OracleBulkCopyImpl, OracleTraceFuncName.ProcessBatch, ex.Message);
				Abort();
				throw ex;
			}
		}

		private int GetInternalBatchSize(int reqBatchSize)
		{
			if (reqBatchSize < 10000)
			{
				return reqBatchSize;
			}
			return 10000;
		}

		internal BulkCopyResult InternalProcessBatch(int numOfRows, bool bUseArray)
		{
			int num = 0;
			int num2 = numOfRows;
			int num3 = 0;
			bool flag = ((m_bulkCopy.NotifyAfter > 0) ? true : false);
			bool flag2 = false;
			bool flag3 = false;
			bool flag4 = false;
			BulkCopyRows rows = new BulkCopyRows(m_DPContext.m_columnsMetaData);
			while (num2 > 0 && !flag2 && !flag3 && !flag4)
			{
				num3 = ((!bUseArray) ? 1 : ((!flag) ? num2 : ((m_numOfRowsToNotify >= num2) ? num2 : m_numOfRowsToNotify)));
				num3 = GetInternalBatchSize(num3);
				num = m_dataSource.GetRows(m_internalColumnMappings, num3, ref rows);
				if (num < num3)
				{
					flag4 = true;
				}
				if (m_bulkCopy.TimeElapsed)
				{
					flag3 = true;
					continue;
				}
				if (flag)
				{
					m_numOfRowsToNotify -= num;
					if (m_numOfRowsToNotify <= 0)
					{
						flag2 = m_bulkCopy.FireRowsCopiedEvent(m_bulkCopy.NotifyAfter - m_numOfRowsToNotify);
						m_numOfRowsToNotify = m_bulkCopy.NotifyAfter;
						if (flag2)
						{
							continue;
						}
					}
				}
				LoadRows(rows);
				num2 -= num;
			}
			BulkCopyResult bulkCopyResult = (BulkCopyResult)0;
			if (flag3)
			{
				bulkCopyResult |= BulkCopyResult.Timeout;
			}
			else if (flag2)
			{
				bulkCopyResult |= BulkCopyResult.UserAbort;
			}
			else
			{
				bulkCopyResult |= BulkCopyResult.Success;
				if (flag4)
				{
					bulkCopyResult |= BulkCopyResult.AllRowRead;
				}
				LoadStream(m_stream);
			}
			return bulkCopyResult;
		}

		internal void Commit()
		{
			m_ttcDPMOP.Init(m_DPContext);
			try
			{
				m_connImpl.m_connectionFreeToUseEvent.WaitOne();
				m_connImpl.AddAllPiggyBackRequests();
				m_ttcDPMOP.Commit();
			}
			finally
			{
				if (m_connImpl.m_autoCommit != m_resetAutoCommit)
				{
					m_connImpl.SetAutoCommit(m_resetAutoCommit);
				}
				m_connImpl.m_connectionFreeToUseEvent.Set();
			}
		}

		internal void Abort()
		{
			m_ttcDPMOP.Init(m_DPContext);
			try
			{
				m_connImpl.m_connectionFreeToUseEvent.WaitOne();
				m_connImpl.AddAllPiggyBackRequests();
				m_ttcDPMOP.Abort();
			}
			finally
			{
				if (m_connImpl.m_autoCommit != m_resetAutoCommit)
				{
					m_connImpl.SetAutoCommit(m_resetAutoCommit);
				}
				m_connImpl.m_connectionFreeToUseEvent.Set();
			}
		}
	}
}
